#pragma once
#include <iostream>
#include <pthread.h>
#include <string>
#include <semaphore.h>
#include <vector>
#include <queue>
#include <assert.h>
#include <sys/types.h>
#include <unistd.h>
#include "Thread.hpp"
#include "Mutex.hpp"

using namespace ThreadSpace;
using namespace std;

const static int thread_nums = 5;
// 提前申明
template <class T>
class ThreadPool;



// 为了能得到当前执行队列任务的线程名称，构建一个大号结构体来当做参数传入
template <class T>
class ThreadData
{
public:
	ThreadPool<T> *threadpool;
	std::string name;

public:
	ThreadData(ThreadPool<T> *tp, const std::string &n) : threadpool(tp), name(n)
	{
	}
};

template <class T>
class ThreadPool
{
private:
	// 在版本2中，每个线程在Handler阶段获取任务队列内部的任务
	// 不同于生产消费者模型，这里的pop类似于handlerTask

	// 但是！这是一个静态方法，没有this指针，无法直接访问成员变量。同封装线程类似，暗度陈仓把this指针当成参数传进来
	static void *HandlerTask(void *args)
	{
        ThreadData<T> *_this = (ThreadData<T> *)args;
		while (true)
		{
			// LockGuard lock(_this->_mutex);
			_this->threadpool->lockQueue();
			// 如果队列内部没有任务，阻塞等待
			while (_this->threadpool->isQueueEmpty())
			{
				_this->threadpool->threadWait();
			}
			// 等待完毕，获取队列内任务并执行
			T task = _this->threadpool->_q.front();
			_this->threadpool->_q.pop();
			// delete lock;
			_this->threadpool->unlockQueue();
			// 在锁外部执行任务
			cout <<_this->name<< "正在处理任务，结果是:" << endl;
			task();
		}
	}

public:
	// 静态成员函数没办法直接访问成员变量
	void lockQueue() { pthread_mutex_lock(&_mutex); }
	void unlockQueue() { pthread_mutex_unlock(&_mutex); }
	bool isQueueEmpty() { return _q.empty(); }
	void threadWait() { pthread_cond_wait(&_cond, &_mutex); }

public:
	// 初始化阶段即创建线程池，接收对应需要的线程个数，然后创建对应线程
	ThreadPool(const int &size = thread_nums)
		: _maxsize(size)
	{
		// 初始化锁和条件变量
		pthread_mutex_init(&_mutex, nullptr);
		pthread_cond_init(&_cond, nullptr);
		// 创建指定数量的线程放入容器中
		for (int i = 0; i < _maxsize; ++i)
		{
			_threads.push_back(new Thread());
		}
	}

	// 版本1.生成对应数量的线程并成功运行对应的任务方法(√)
	void run()
	{
		for (int i = 0; i < _maxsize; ++i)
		{
			
			// ThreadData<T> task(this, _threads[i]->getname());
			ThreadData<T> *td = new ThreadData<T>(this, _threads[i]->getname());
				_threads[i]->start(HandlerTask, td);
			logMessage(DEBUG, "%s start ...",  _threads[i]->getname());
		}
	}

	// 版本2.放入任务，以类似环形队列的方式让进程获取任务并执行任务。其中，线程们获取任务的顺序由队列决定
	void push(const T &task)
	{
		LockGuard lock(&_mutex);
		_q.push(task);
		pthread_cond_signal(&_cond);
	}
	~ThreadPool()
	{
		pthread_mutex_destroy(&_mutex);
		pthread_cond_destroy(&_cond);

		for (int i = 0; i < _maxsize; ++i)
		{
			delete _threads[i];
		}
	}

private:
	// 存放任务的队列
	queue<T> _q;
	// 锁，条件变量保护队列
	pthread_mutex_t _mutex;
	pthread_cond_t _cond;

	// 一个容器来存放线程
	vector<Thread *> _threads;
	int _maxsize;
};

